#pragma once

#define FILTER_MAJOR_NDIS_VERSION	6
//#define NTDDI_VERSION NTDDI_WIN7

//#include <wdm.h>
#include <ntifs.h>
#pragma warning(push)
#pragma warning(disable:4201)
#include <fwpmk.h>
#include <fwpsk.h>
#pragma warning(pop)

#define INITGUID
#include <guiddef.h>
#include <ntstrsafe.h>

#if defined(NDIS60)
#define FILTER_MAJOR_NDIS_VERSION	0
#elseif defined(NDIS620)
#define FILTER_MAJOR_NDIS_VERSION	20
#elseif	defined(NDIS630)
#define FILTER_MAJOR_NDIS_VERSION	30
#endif

#ifndef MAX_PATH
#define MAX_PATH	260
#endif

#define WFP_DEVICE_NAME		L"\\Device\\wfp_filter_device"
#define WFP_SYM_LINK_NAME	L"\\DosDevices\\wfp_filter_device"
#define WFP_FILTER_ESTABLISTED_CALLOUT_DISPLAY_NAME	L"WfpFilterEstablishedCalloutName"
#define WFP_FILTER_SUB_LAYER_DISPLAY_NAME			L"WfpFilterSubLayerName"
#define WFP_FILTER_ESTABLISH_DISPLAY_NAME			L"WfpFilterEstablishName"

#define IOCTL_WFP_FILTER_ADD_RULE	CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_READ_ACCESS|FILE_WRITE_ACCESS)
#define IOCTL_WFP_FILTER_DEL_RULE	CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_READ_ACCESS|FILE_WRITE_ACCESS)
#define IOCTL_PID_FILTER_ADD_RULE	CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_READ_ACCESS|FILE_WRITE_ACCESS)
#define IOCTL_PID_FILTER_DEL_RULE	CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_READ_ACCESS|FILE_WRITE_ACCESS)


//[Guid("095C8AF2-E527-4C3B-8894-C1E1C4414472")]
DEFINE_GUID(WFP_FILTER_ESTABLISHED_CALLOUT_V4_GUID, 0x095C8AF2, 0xE527, 0x4C3B, 0x88, 0x94, 0xC1, 0xE1, 0xC4, 0x41, 0x44, 0x72);
//[Guid("5EEE30F3-0890-47D5-8B9E-8DE09D94378B")]
DEFINE_GUID(WFP_FILTER_SUBLAYER_GUID, 0x5EEE30F3, 0x0890, 0x47D5, 0x8B, 0x9E, 0x8D, 0xE0, 0x9D, 0x94, 0x37, 0x8B);


typedef struct LOG_LIST
{
	LIST_ENTRY listNode;
	UNICODE_STRING msg;
}LOG_LIST, *PLOG_LIST;

VOID DriverUnload(IN DRIVER_OBJECT* pDriverObj);

PDEVICE_OBJECT CreateDevice(IN DRIVER_OBJECT* pDriverObj);

NTSTATUS WfpFilterIRPDispatch(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);
NTSTATUS WfpFilterDeviceRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp);

NTSTATUS WfpRegisterCalloutImple(IN OUT PVOID pDevObj, 
	IN FWPS_CALLOUT_CLASSIFY_FN pfClassifyFunc,
	IN FWPS_CALLOUT_NOTIFY_FN pfNotifyFunc,
	IN FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN pfFlowDeleteFunc,
	IN GUID const* pCalloutKey,
	IN UINT32 uFlags,
	OUT UINT32* puCalloutId);

NTSTATUS WfpRegisterCallouts(IN OUT PVOID pDevObj);

VOID NTAPI WfpFilterEstablishedClassifyFnV4(
	IN const FWPS_INCOMING_VALUES* pInFixedValues,
	IN const FWPS_INCOMING_METADATA_VALUES* pInMetaValues,
	IN OUT void* pLayerData,
	IN OPTIONAL const void* pClassifyContext,
	IN const FWPS_FILTER* pFilter,
	IN UINT64 flowContext,
	OUT FWPS_CLASSIFY_OUT* pClassifyOut);

NTSTATUS NTAPI WfpFilterEstablishedNotifyFnV4(IN FWPS_CALLOUT_NOTIFY_TYPE notifyType, IN const GUID* filterKey, IN const FWPS_FILTER* filter);

VOID NTAPI WfpFilterEstablishedFlowDelete(IN UINT16 layerId, IN UINT32 calloutId, IN UINT64 flowContext);

NTSTATUS WfpAddCallouts();

NTSTATUS WfpRegisterCallouts(IN OUT PVOID pDevObj);

NTSTATUS WfpAddSubLayer();

NTSTATUS WfpAddFilters();

VOID WfpRemoveSubLayer();

VOID WfpRemoveFilters();

VOID WfpUnRegisterCallouts();

VOID WfpRemoveCallouts();

HANDLE OpenEngine();
VOID CloseEngine();

NTSTATUS InitWfp();

VOID UninitWfp();

VOID DeleteDevice();

VOID StartThread();

VOID WriteLog(PUNICODE_STRING strBuffer);